import json

from PIL import ImageFont

from src import graphics
from src.graphics import (
    draw_rounded_rectangle,
    get_image,
    get_title,
    color,
    difficulty_mapping,
    create_rating_image
)


def draw_box(draw, pic, x: int, y: int, width: int, height: int, info: dict, is_b30: bool):
    """
    绘制单个成绩格子
    
    Args:
        draw: PIL ImageDraw对象
        pic: PIL Image对象
        x: 格子左上角x坐标
        y: 格子左上角y坐标
        width: 格子宽度
        height: 格子高度
        info: 成绩信息字典,包含:
            - music: 歌曲信息(name, jacket等)
            - difficulty: 难度
            - score: 分数
            - constant: 定数(可选)
            - rating: Rating值
        is_b30: 是否为B30视图(True)还是B30R10视图(False)
    """
    # 绘制白色背景
    draw_rounded_rectangle(draw, (x, y, x + width, y + height), 10, fill=(255, 255, 255))

    # 绘制歌曲封面
    pic.paste(get_image(info['music']['jacket']).resize((158, 158)), (x + 10, y + 10))

    # 获取并绘制歌曲标题
    title = get_title(info['music']['name'], width)
    title_color = _get_title_color(info['difficulty'])
    draw.text(
        (x + 180, y + 10),
        title,
        fill=title_color,
        font=ImageFont.truetype('assets/fonts/MSYHBD.TTC', 30)
    )

    if is_b30:
        _draw_b30_box(draw, pic, x, y, info)
    else:
        _draw_b30r10_box(draw, pic, x, y, info)


def _get_title_color(difficulty):
    """
    获取歌曲标题颜色
    
    Args:
        difficulty: 难度等级(数字或字符串)
        
    Returns:
        tuple: RGB颜色值
    """
    if isinstance(difficulty, (int, str)) and str(difficulty) in ['0', '1', '2', '3', '4', '5']:
        return color[difficulty_mapping[str(difficulty)]]
    return color[difficulty.lower()]


def _draw_b30_box(draw, pic, x: int, y: int, info: dict):
    """
    绘制B30视图的成绩格子内容
    
    Args:
        draw: PIL ImageDraw对象
        pic: PIL Image对象
        x: 格子左上角x坐标
        y: 格子左上角y坐标
        info: 成绩信息字典
    """
    # 绘制分数
    font_score = ImageFont.truetype('assets/fonts/consolab.ttf', 60)
    draw.text((x + 180, y + 60), str(info['score']), fill=(0, 0, 0), font=font_score)

    # 获取并绘制定数
    constant = _get_constant(info)
    draw.text(
        (x + 180, y + 110),
        f"{constant if constant != 0 else '00.0'}  >",
        fill=(0, 0, 0),
        font=ImageFont.truetype('assets/fonts/MSYHBD.TTC', 45)
    )

    # 绘制Rating值
    rating = create_rating_image(info['rating'])
    rating = rating.resize((int(rating.size[0] * 1.65), int(rating.size[1] * 1.65)))
    pic.paste(rating, (x + 350, y + 120))


def _draw_b30r10_box(draw, pic, x: int, y: int, info: dict):
    """
    绘制B30R10视图的成绩格子内容
    
    Args:
        draw: PIL ImageDraw对象
        pic: PIL Image对象
        x: 格子左上角x坐标
        y: 格子左上角y坐标
        info: 成绩信息字典
    """
    # 绘制分数
    font_score = ImageFont.truetype('assets/fonts/consolab.ttf', 45)
    draw.text((x + 180, y + 60), str(info['score']), fill=(0, 0, 0), font=font_score)

    # 绘制Rating值
    rating = create_rating_image(info['rating'])
    rating = rating.resize((int(rating.size[0] * 2), int(rating.size[1] * 2)))
    pic.paste(rating, (x + 180, y + 110))


def _get_constant(info: dict) -> float:
    """
    获取歌曲定数,如果info中没有则从music.json中读取
    
    Args:
        info: 成绩信息字典
        
    Returns:
        float: 歌曲定数
    """
    if 'constant' in info:
        return info['constant']

    with open('assets/music.json', 'r', encoding='utf-8') as f:
        music = json.load(f)

    if info['music']['name'] not in music:
        print(f"ALERT: {info['music']['name']} not in music.json")
        return 0

    difficulty = graphics.difficulty_mapping_up[info['difficulty']]
    if difficulty not in music[info['music']['name']]:
        print(f"ALERT: {difficulty} not in {info['music']['name']}")
        return 0

    return music[info['music']['name']][difficulty]
